package edu.zju.gis.dbfg.model.etl;

import edu.zju.gis.dbfg.common.exception.ModelFailedException;
import edu.zju.gis.dbfg.common.util.DateUtils;
import edu.zju.gis.dbfg.model.scala.MIngest;
import edu.zju.gis.dbfg.model.statistic.AreaStatistic;
import edu.zju.gis.dbfg.model.tile.GeotrellisTileOptions;
import edu.zju.gis.dbfg.model.tile.TileServiceFromEs;
import geotrellis.raster.render.ColorMap;
import org.apache.spark.SparkConf;
import org.apache.spark.api.java.JavaSparkContext;
import org.gdal.gdal.Band;
import org.gdal.gdal.Dataset;
import org.gdal.gdal.gdal;
import org.gdal.gdalconst.gdalconstConstants;
import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.math.BigInteger;
import java.sql.*;
import java.util.UUID;

public class TileServiceFromTiff {
    private final static Logger logger = LoggerFactory.getLogger(TileServiceFromEs.class);
    private static String publisher = "admin";
    private static String tileServerTail = "/geotrellis/{z}/{x}/{y}/";//with no band
    private static String userSpaceRoot = "/opt/shengting/userSpace/";

    public static void main(String[] args) {

        // Setup model arguments
        logger.info("Setup arguments");
        TileServiceFromTiffArgs mArgs = TileServiceFromTiffArgs.initArgs(args);
        if (mArgs == null) {
            String msg = "init args failed, exit";
            logger.error(msg);
            throw new ModelFailedException(AreaStatistic.class, "main()", msg, args);
        }

        String id = UUID.randomUUID().toString();
        String tileServerAddress = mArgs.getTileServerAddress();//input
        String layerName = mArgs.getLayerName();//input
        String tiffPath = mArgs.getTiffPath();//input
        String bandsArray = mArgs.getBandsArray();//input
        String keyWords = mArgs.getKeyWords();//input
        String topic = mArgs.getTopic();//input
        String serviceURL = tileServerAddress + id + tileServerTail;
        String output = userSpaceRoot + mArgs.getUserId() + "/mapServices";
//        String output = "C:\\Data\\dbfg\\test0407\\lcra0410";

        String[] bands = bandsArray.split("#");

        gdal.AllRegister();
        Dataset dataset = gdal.Open(tiffPath, gdalconstConstants.GA_ReadOnly);
        if (dataset == null) {
            System.out.println("GDAL read error: " + gdal.GetLastErrorMsg());
        }

        SparkConf conf = new SparkConf()
//                .setMaster("local[4]")
                .setAppName("Map Service Example");
        JavaSparkContext jsc = new JavaSparkContext(conf);

        Connection conn;
        PreparedStatement stmt;
        String driver = "com.mysql.cj.jdbc.Driver";
        String url = "jdbc:mysql://101.132.255.121:3306/shengting?allowMultiQueries=true&useUnicode=true&characterEncoding=UTF-8&useSSL=false&serverTimezone=GMT%2B8";
        String user = "root";
        String password = "root";
        String sql = "insert into tb_service values (?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?,?)";
        String sqlField = "insert into tb_service_field_info values (?,?,?,?,?,?,?)";
        String updateSql = "update tb_service set status = ? where id = ?";

        double[] transform = dataset.GetGeoTransform();
        int xsize = dataset.getRasterXSize();
        int ysize = dataset.getRasterYSize();
        double xmin = transform[0] < (transform[0] + transform[1] * xsize) ? transform[0] : (transform[0] + transform[1] * xsize);
        double xmax = transform[0] >= (transform[0] + transform[1] * xsize) ? transform[0] : (transform[0] + transform[1] * xsize);
        double ymin = transform[3] < (transform[3] + transform[5] * ysize) ? transform[3] : (transform[3] + transform[5] * ysize);
        double ymax = transform[3] >= (transform[3] + transform[5] * ysize) ? transform[3] : (transform[3] + transform[5] * ysize);

        JSONObject tiffInfo = new JSONObject();
        JSONArray raster_information_1 = new JSONArray();
        JSONObject raster_information = new JSONObject();
        raster_information.put("columns", xsize);
        raster_information.put("rows", ysize);
        raster_information.put("number of bands", dataset.getRasterCount());
        String proj = dataset.GetProjectionRef();
        raster_information.put("spatial reference", "EPSG:" + proj.substring(proj.length() - 7, proj.length() - 3));
        raster_information_1.put(raster_information);
        tiffInfo.put("raster_information", raster_information_1);

        JSONArray extent_1 = new JSONArray();
        JSONObject extent = new JSONObject();
        extent.put("top", xmin);
        extent.put("left", ymin);
        extent.put("right", ymax);
        extent.put("bottom", xmax);
        extent_1.put(extent);
        tiffInfo.put("extent", extent_1);

        JSONArray statistics = new JSONArray();
        for (int i = 0; i < dataset.getRasterCount(); i++) {
            JSONObject bandInfo = new JSONObject();
            Band band = dataset.GetRasterBand(i + 1);
            double[] minmax = new double[2];
            band.ComputeRasterMinMax(minmax);
            bandInfo.put("bandIndex", i + 1);
            bandInfo.put("min", minmax[0]);
            bandInfo.put("max", minmax[1]);
            statistics.put(bandInfo);
        }
        tiffInfo.put("statistics", statistics);

        try {
            Class.forName(driver);
            conn = DriverManager.getConnection(url, user, password);
            stmt = conn.prepareStatement(sql);
            stmt.setString(1, publisher);
            stmt.setString(2, id);
            stmt.setString(3, layerName);
            stmt.setString(4, serviceURL);
            stmt.setString(5, keyWords);
            stmt.setString(6, "TMS");
            stmt.setString(7, topic);
            stmt.setString(8, "WGS84");
            stmt.setString(9, "经纬度");
            stmt.setString(10, String.format("%.9f,%.9f,%.9f,%.9f", xmin, xmax, ymin, ymax));
            stmt.setTimestamp(11, Timestamp.valueOf(DateUtils.curDateTimeStrDefault()));
            stmt.setString(12, "");
            stmt.setString(13, "***/topography.png");
            stmt.setString(14, mArgs.getUserId());
            stmt.setString(15, tiffInfo.toString());
            stmt.setString(16, "raster");
            stmt.setString(17, tiffPath.substring("//".length()));
            stmt.setString(18, "loading");
            stmt.executeUpdate();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (SQLException e) {
            e.printStackTrace();
        }

        try {
            MIngest.run(jsc.sc(), tiffPath, output, layerName, 4);

            try {
                Class.forName(driver);
                conn = DriverManager.getConnection(url, user, password);
                for (int i = 0; i < bands.length; i++) {
                    Band band = dataset.GetRasterBand(Integer.parseInt(bands[i]));
                    double[] minmax = new double[2];
                    band.ComputeRasterMinMax(minmax);
                    stmt = conn.prepareStatement(sqlField);
                    stmt.setString(1, UUID.randomUUID().toString());
                    stmt.setString(2, id);
                    stmt.setString(3, "Band" + Integer.parseInt(bands[i]));
                    stmt.setString(4, String.valueOf(i));
                    stmt.setString(5, "CDouble");
                    stmt.setString(6, minmax[0] + "##" + minmax[1]);

                    GeotrellisTileOptions fieldsColorMap = new GeotrellisTileOptions();
                    fieldsColorMap.setFieldType("CDouble");
                    int min = Double.valueOf(minmax[0]).intValue();
                    int max = Double.valueOf(minmax[1]).intValue() + 1;
                    fieldsColorMap.setMin(min);
                    fieldsColorMap.setMax(max);
                    fieldsColorMap.setColorRampIndex(1);
                    ColorMap.Options options = new ColorMap.Options(edu.zju.gis.dbfg.model.scala.GeoTrellisTile.getClassBoundaryType(), 0x00000000, 0x00000000, false);
                    ColorMap cm = null;
                    BigInteger sc = new BigInteger(fieldsColorMap.getStartColor(), 16);
                    BigInteger ec = new BigInteger(fieldsColorMap.getEndColor(), 16);
                    int startColor = sc.intValue();
                    int endColor = ec.intValue();
                    int stops = fieldsColorMap.getStops();
                    double gap = (max - min) * 1.0 / stops;
                    double[] stopVals = new double[stops];
                    for (int j = 0; j < stopVals.length; j++) {
                        stopVals[j] = (min + j * gap);
                    }
                    cm = edu.zju.gis.dbfg.model.scala.GeoTrellisTile.getCustomContinouesColorMap(startColor, endColor, min, max, stopVals, options);

                    stmt.setString(7, cm.breaksString());
                    stmt.executeUpdate();

                    stmt = conn.prepareStatement(updateSql);
                    stmt.setString(1, "succeeded");
                    stmt.setString(2, id);
                    stmt.executeUpdate();
                }
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        } catch (Exception ex) {
            try{
                Class.forName(driver);
                conn = DriverManager.getConnection(url, user, password);
                stmt = conn.prepareStatement(updateSql);
                stmt.setString(1, "failed");
                stmt.setString(2, id);
                stmt.executeUpdate();
            }catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (SQLException e) {
                e.printStackTrace();
            }
        }

    }
}
